/*****************************************************************************************/
/* ECSE 426 - Microprocessor - Fall 2009
/* Lab Experiment 3 - Includes control for UART0 (Keyboard) and UART1 (SPI to cc2500)
/* UART.C
/* @author: Danny Wu - 260238209 - B.Comp.Eng
/* @author: Han-Sheng Chin - 260209715 - B.Elec.Eng
/* @version: 09.10.23.1508 
/****************************************************************************************/

#include <uart.h>
#include <constants.h>
//control for debug mode
#define DEBUG_MODE FALSE
//general constants
#define TRUE 1
#define FALSE 0
//spi address constants
#define SPI_READ 0x80
#define SPI_WRITE 0x00
#define CSn_PIN 0x01
#define USART1_SIMO   0x02
#define USART1_SOMI   0x04
#define USART1_UCLK   0x08

// Global variables from main.c
extern int state;   
extern int func;    
extern int exit;
extern int input;
extern int waitInput;
extern char regAdd;
extern char regVal;
extern char msg[64];
extern int msgCtr;
// Local variables
int inputCount = 0;
char inputOne, inputTwo;

//initRsUART
void initRsUART(void){
  unsigned int i;  
  do {
    IFG1 &= ~OFIFG;                       // Clear OSCFault flag
    for (i = 0xFF; i > 0; i--);           // Time for flag to set
  } while ((IFG1 & OFIFG) != 0);          // OSCFault flag still set?          
  UCTL0 = CHAR;                         // 8-bit character
  UTCTL0 = SSEL1;                       // UCLK = SMCLK //SSEL0 = ACLOCK
  UBR00 = 0x8A;                         // 8Mhz/57600 - 0x8a
  UBR10 = 0x00;                         // 
  UMCTL0 = 0x00;                        // no modulation
  ME1 |= UTXE0 + URXE0;                 // Enable USART0 TXD
  IE1 |= URXIE0;                        // Enable USART0 RX interrupt
  P3SEL |= 0x30;                        // P3.4,5 = USART0 TXD/RXD
  P3DIR |= 0x10;                        // P3.4 output direction
  _EINT();                              // Enable interrupts   
}//end main

//interrupt for receiving from UART0
void usart0_rx (void) __interrupt[UART0RX_VECTOR] {
  while ((IFG1 & UTXIFG0) == 0);        // USART0 TX buffer ready?
  
  switch (func) {
    case 0: // main menu
      switch(RXBUF0) {
        case 0x31: // key '1': dump all registers
          putChar('\b');
          putChar(RXBUF0);
          input = 1;
          break;
        case 0x32: // key '2': modify a register
          putChar('\b');
          putChar(RXBUF0);
          input = 2;
          break;
        case 0x33: // key '3': send and receive
          putChar('\b');
          putChar(RXBUF0);
          input = 3;
          break;
        case 0x34: // key '4': receive only
          putChar('\b');
          putChar(RXBUF0);
          input = 4;
          break;
        case 0x1b: // escape key exits program
          exit = 1;
          break;
        case 0x0d: // enter key
          state = input;
          input = 0;
          break;
        case 0x08: //backspace
          putChar('\b');
          putChar(0x20);
          //putChar('\b');       
          break;
        default:
//          println(" Invalid input! ");
//          putChar(RXBUF0);
//          println("Select an option:  ");
          break;
      } // end nested switch of case func=0
      break;
    case 1:                                                  // Option to print menu or exit at the end of each function.
      switch(RXBUF0) {
        case 0x0d: // enter key
          state = 0;
          break;
        case 0x1b: // escape key
          exit = 1;
          break;
        default:
          break;
      } // end nested switch of case func=1
      break;
    case 2:                                                // Modify register mode - input register address
      switch(RXBUF0) {
        case 0x1b: // excape key
          println("Operation aborted!");
          state = 0;
          func = 0;
          waitInput = 0;
          break;
        case 0x0d: // enter key
          if (inputCount == 2)
          {

            regAdd = combineInput(inputOne, inputTwo);        // Combine the two inputs into one. Function not written yet.
            println("Register address is: ");
            printHex(regAdd); //debug

            inputCount = 0;
            waitInput = 0;
          }
          else
          {
            println("Invalid input! Press escape to return to menu!");
          }
          break;
        default:
          // Store the value of the register address.
          if (inputCount == 0)
          {
            inputOne = RXBUF0;
            putChar(inputOne);
            inputCount++;
          }
          else if (inputCount == 1)
          {
            inputTwo = RXBUF0;
            putChar(inputTwo);
            inputCount++;
          }
          break;
      } // end nested switch of case func=2
      break;
    case 3:                                                // Modify register mode - input register value
      switch(RXBUF0) {
        case 0x1b: // excape key
          println("Operation aborted!");
          state = 0;
          func = 0;
          waitInput = 0;
          break;
        case 0x0d: // enter key
          if (inputCount == 2)
          {

            regVal = combineInput(inputOne, inputTwo);        // Combine the two inputs into one. Function not written yet.
            println("New register value is ");

            printHex(regVal); //debug
            inputCount = 0;
            waitInput = 0;
            spiWriteReg(regAdd, regVal);
            println("Register changed!");
          }
          else
          {
            println("Invalid input! Press escape to return to menu!");
          }
          break;
        default:
          // Store the new value of the register.
          if (inputCount == 0)
          {
            inputOne = RXBUF0;
            putChar(inputOne);
            inputCount++;
          }
          else if (inputCount == 1)
          {
            inputTwo = RXBUF0;
            putChar(inputTwo);
            inputCount++;
          }
          break;
      } // end nested switch of case func=3
      break;

      case 5:
        switch(RXBUF0) {
          case 0x08: //backspace
            putChar('\b');
            putChar(0x20);
            putChar('\b');  
            msgCtr--;
            msg[msgCtr] = 0;           
            break;
          case 0x0d: // enter key
            spiWriteReg(regAdd, regVal);
            waitInput = 0;
            break;
          case 0x1b: // escape key
            println("Operation aborted!");
            state = 0;
            func = 0;
            waitInput = 0;
            break;
          default:
            msg[msgCtr] = RXBUF0;
            putChar(msg[msgCtr]);
            msgCtr++;
            break;
        } // end nested switch of case func=5
        break;
  } // end switch
}//end usart0_rx



//initSpiUART
void initSpiUART(void) {

  //TI_CC_SPISetup(); //calling TI code
  P5OUT |= CSn_PIN;
  P5DIR |= CSn_PIN;               // /CS disable

  ME2 |= USPIE1;                            // Enable USART1 SPI mode
  U1CTL |= CHAR + SYNC + MM + SWRST;        // 8-bit SPI Master **SWRST**
  U1TCTL |= CKPL + SSEL0 + STC;             // SMCLK, 3-pin mode
  U1BR0 = 0x02;                             // UCLK/2
  U1BR1 = 0x00;                             // 0
  U1MCTL = 0x00;                            // No modulation
  P5SEL |= USART1_SIMO | USART1_SOMI | USART1_UCLK;
                                            // SPI option select
  P5DIR |= USART1_SIMO + USART1_UCLK;
                                            // SPI TXD out direction
  UCTL1 &= ~SWRST;                          // Initialize USART state machine
}// end initSpiUART


//write single byte to CC2500
void spiWriteReg(char addr, char value) {

      //TI_CC_SPIWriteReg(addr, value);
    P5OUT &= ~CSn_PIN;                        // /CS enable
    while (P5IN&USART1_SOMI);               // Wait for CC2500 ready
    IFG2 &= ~URXIFG1;                       // Clear flag from first dummy byte
    TXBUF1 = addr;                         // Send address
    while ((IFG2 & URXIFG1) == 0);                // Wait for TX` to finish
    IFG2 &= ~URXIFG1;                       // Clear flag from first dummy byte
    TXBUF1 = value;                        // Send value
    while ((IFG2 & URXIFG1) == 0);                // Wait for end of data TX
    P5OUT |= CSn_PIN;                       // --CS disable (set to high)
}// end spiWriteReg


//read the registers from an address on the CC2500
char spiReadReg(char addr){
  char x;
  int i;

  if(addr > 0x2F && addr < 0x3E){ //make sure you read STATUS 
    addr += 0xC0;
  }else{
    addr = (addr | SPI_READ);
  }//end if

  P5OUT &= ~CSn_PIN;        // /CS enable
  while (P5IN&USART1_SOMI);// Wait for CCxxxx ready
  wait(400); //wait
  IFG2 &= ~UTXIFG1;        // Clear flag set during addr TX
  U1TXBUF = addr; // Send address
  while (!(IFG2&URXIFG1));                  // Wait for TXBUF ready
  wait(400); //wait
  IFG2 &= ~URXIFG1;                         // Clear flag set during addr TX
  U1TXBUF = 0;                              // Load dummy byte for TX after addr
  while (!(IFG2&UTXIFG1));                  // Wait for end of dummy byte TX
  wait(400); //wait
  x = U1RXBUF;                              // Read data
  P5OUT |= CSn_PIN;         // /CS disable
  return x;
}//end spiReadReg

/**
 * Generates a random char
 *   
 */
char getRndChar(void){
  char rnd_element = 33 + rand() % 127;
  return rnd_element;
}//end rand


/**
 * print a string of char on the UART0 = Hyper Terminal
 */
void print(char* text){
  int ctr;
  for(ctr=0;text[ctr] != '\0';ctr++)
    putChar(text[ctr]);
}//end print



/**
 * println with a \n before
 * print a string of char on the UART0 = Hyper Terminal
 */
void println(char* text){
  int ctr;
  putChar(0x0D); //carriage return
  putChar('\n'); //line feed
  for(ctr=0;text[ctr] != '\0';ctr++)
    putChar(text[ctr]);
}//end println

/**
 * putChar on the UART0 = Hyper Terminal
 */
void putChar(char text){
  if(DEBUG_MODE){
    debug_printf("%d",text);
    debug_printf("%x",text);
  }else{    
    while ((IFG1 & UTXIFG0) == 0);        // USART0 TX buffer ready?
    TXBUF0 = text;                        // RXBUF0 to TXBUF0
  }//end if else
}//end putchar

/**
 * Clears the terminal
 * by shifting the output up.
 */
void clearScreen(void){
  putChar(0xC);
}//end getchar

/**
 * Displays the char value into a hex equivalent
 */
void printHex(char input) {
  int i, j, k;
  int hex[2];
  char charHex[2];

  k = input; //convert into decimal
  hex[0] = k/16; //retrieve first hex
  hex[1] = k%16; //retrieve second hex
  for(i = 0; i < 2;i++){
    j = hex[i];
    if (j<10) {
        charHex[i] = j+48;
    } else if (j == 10) {
        charHex[i] = 'A';
    } else if (j == 11) {
        charHex[i] = 'B';
    } else if (j == 12) {
        charHex[i] = 'C';
    } else if (j == 13) {
        charHex[i] = 'D';
    } else if (j == 14) {
        charHex[i] = 'E';
    } else if (j == 15) {
        charHex[i] = 'F';
    } //end else if 
  }//end for

  //print out char value representing the hex
  print("0x");
  putChar(charHex[0]);
  putChar(charHex[1]);
}//end charToHex

/**
 * combines 2 Hex values and put them as 1
 * ie: enter A, B, represented as 0xAB
 * This function should be used when you receive a value from the UART
 * and you want to convert it into 1 byte. Handles lower and upper case values.
 * @return (char combined)  
 */
char combineInput(char firstInput, char secondInput) {  
  int i,j,k;
  char combined=0x00;
  char inputs[2];
  inputs[0] = firstInput;
  inputs[1] = secondInput;

  for(i=0; i<2;i++){
    switch(inputs[i]){
      case '0':
        combined |= 0x00;
        break;
      case '1':
        combined |= 0x01;
        break;
      case '2':
        combined |= 0x02;
        break;
      case '3':
        combined |= 0x03;
        break;
      case '4':
        combined |= 0x04;
        break;
      case '5':
        combined |= 0x05;
        break;
      case '6':
        combined |= 0x06;
        break;
      case '7': 
        combined |= 0x07;  
        break;
      case '8':
        combined |= 0x08;
        break;
      case '9':
        combined |= 0x09;
        break;
      case 'A':
      case 'a':
        combined |= 0x0A;
        break;
      case 'B':
      case 'b':
        combined |= 0x0B;
        break;
      case 'C':
      case 'c':
        combined |= 0x0C;
        break;
      case 'D':
      case 'd':
        combined |= 0x0D;
        break;
      case 'E':
      case 'e':
        combined |= 0x0E;
        break;
      case 'F':
      case 'f':
        combined |= 0x0F;
        break;
      default:
        break;
    }//end switch
    
    //if first input, then shift to most sign.
    if(i==0)
      combined = combined << 4;
  }//end for
  
  return combined;
}//end combineInput

//this function is used to create a wait for the system
void wait(int microseconds){
  int i;
  for(i=0;i<microseconds;i++){};
}//end wait function
